package net.oschina.renyong.query.generator;

import java.io.*;
import java.util.Map;
import java.util.Properties;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.app.VelocityEngine;
import org.springframework.util.StringUtils;

import com.baomidou.mybatisplus.generator.config.ConstVal;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;

import net.oschina.renyong.query.generator.constant.QuerySqlConstant;
import net.oschina.renyong.query.generator.po.ContentQuery;

/**
 * 查询文件代码生成器
 * @author Timothy
 */
public class QueryFileGenerator {

	private static final String AUTHOR_DEFAULT = "idea";
	/**
	 * velocity引擎
	 */
	private static VelocityEngine engine;

	/**
	 * 生成velocity context
	 * @param contentQuery ContentQuery
	 * @param packageMap 各个待生成类所在的包路径
	 * @param globalConfig 全局配置
	 * @return VelocityContext
	 */
	public static VelocityContext generateVelocity(ContentQuery contentQuery, Map<String, String> packageMap,
			GlobalConfig globalConfig) {
		String author = globalConfig.getAuthor() != null ? globalConfig.getAuthor() : AUTHOR_DEFAULT;

		VelocityContext ctx = new VelocityContext();
		ctx.put("package", packageMap);
		ctx.put("author", author);
		ctx.put("contentQuery", contentQuery);
		ctx.put("entity", contentQuery.getEntityName());
		ctx.put("entityColumnConstant", true);
		ctx.put("entityBuilderModel", true);
		return ctx;
	}

	/**
	 * 生成一组代码文件
	 * @param contentQuery ContentQuery
	 * @param context VelocityContext
	 * @param pathInfo 各个待生成文件的目录地址
	 */
	public static void batchOutput(ContentQuery contentQuery, VelocityContext context, Map<String, String> pathInfo) {
		String entityFile = pathInfo.get(ConstVal.ENTITY_PATH) + File.separator + contentQuery.getEntityName()
				+ ConstVal.JAVA_SUFFIX;
		String mapperFile = pathInfo.get(ConstVal.MAPPER_PATH) + File.separator + contentQuery.getMapperName()
				+ ConstVal.JAVA_SUFFIX;
		String xmlFile = pathInfo.get(ConstVal.XML_PATH) + File.separator + contentQuery.getXmlName()
				+ ConstVal.XML_SUFFIX;
		String serviceFile = pathInfo.get(ConstVal.SERVICE_PATH) + File.separator + contentQuery.getServiceName()
				+ ConstVal.JAVA_SUFFIX;
		String implFile = pathInfo.get(ConstVal.SERVICE_IMPL_PATH) + File.separator + contentQuery.getServiceImplName()
				+ ConstVal.JAVA_SUFFIX;

		try {
			// entity
			vmToFile(context, QuerySqlConstant.TEMPLATE_VIEW_ENTITY, entityFile);
			// mapper
			vmToFile(context, QuerySqlConstant.TEMPLATE_VIEW_MAPPER, mapperFile);
			// xml
			vmToFile(context, QuerySqlConstant.TEMPLATE_VIEW_XML, xmlFile);
			// service
			vmToFile(context, QuerySqlConstant.TEMPLATE_VIEW_SERVICE, serviceFile);
			// serviceImpl
			vmToFile(context, QuerySqlConstant.TEMPLATE_VIEW_SERVICEIMPL, implFile);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 将模板转化成为文件
	 * @param context 内容对象
	 * @param templatePath 模板文件
	 * @param outputFile 文件生成的目录
	 */
	private static void vmToFile(VelocityContext context, String templatePath, String outputFile) throws IOException {
		if (StringUtils.isEmpty(templatePath)) {
			return;
		}
		VelocityEngine velocity = getVelocityEngine();
		Template template = velocity.getTemplate(templatePath, ConstVal.UTF8);
		FileOutputStream fos = new FileOutputStream(outputFile);
		BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(fos, ConstVal.UTF8));
		template.merge(context, writer);
		writer.close();
		System.out.println("模板:" + templatePath + ";  文件:" + outputFile);
	}

	/**
	 * 设置模版引擎，主要指向获取模版路径
	 */
	private static VelocityEngine getVelocityEngine() {
		if (engine == null) {
			Properties p = new Properties();
			p.setProperty(ConstVal.VM_LOAD_PATH_KEY, ConstVal.VM_LOAD_PATH_VALUE);
			p.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH, "");
			p.setProperty(Velocity.ENCODING_DEFAULT, ConstVal.UTF8);
			p.setProperty(Velocity.INPUT_ENCODING, ConstVal.UTF8);
			// p.setProperty(Velocity.OUTPUT_ENCODING, ConstVal.UTF8);
			p.setProperty("file.resource.loader.unicode", "true");
			engine = new VelocityEngine(p);
		}
		return engine;
	}

}
